package io.yunho.srw.lean.stream;

import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by Administrator on 2019/12/23.
 * 一、Steam 的三个操作步骤：
 * 1、创建Stream
 *
 * 2、中间操作
 *
 * 3、终止操作
 */
public class TestStream {
    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,555.5,"free"),
            new Employee("李四",21,99555.5,"free"),
            new Employee("王五",41,199555.5,"busy"),
            new Employee("赵六",71,16555.5,"busy"),
            new Employee("田七",11,19255.5,"busy")
    );

    //创建stream
    @Test
    public void test1(){
        //1、可以通过collection系列集合提供的stream()或者parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stringStream = list.stream();
        //2、通过Arrays 中的静态方法 stream 获取数据连接
        String[] strings = new String[10];
        Stream<String> stringStream1 = Arrays.stream(strings);
        //3、通过Stream中的静态方法 of方法
        Stream<String> stringStream2 =Stream.of("aa","bb");
        //4、创建无限流
        //迭代
        Stream<Integer>  integerStream = Stream.iterate(0,x->x+2);
        integerStream.limit(15).forEach(System.out::println);

        //5、生成
        Stream.generate(()->Math.random())
                .limit(10)
                .forEach(System.out::println);
    }
    //中间操作
    /**
     * 筛选与切片
     * filter-- 接受lambda，从流中排除某些元素
     * limit--截断流， 使其元素不超过给定数量
     * skip（n）--跳过元素，返回一个扔掉前n个元素的流，若流中元素不足n个，则返回空流，与limit互补
     * distinct -- 筛选，通过流所产生的元素的hashcode和equals去重元素
     */
    //内部迭代，由stream api 内部完成
    @Test
    public void test2(){
        //中间操作
        List<String> list = Arrays.asList("李四","张三","王五");
        Stream stream =list.stream()
                .filter(x->{
                    System.out.println("中间操作");
                    return x.contains("李");
                });
        //终止操作 “惰性求值”：一次性执行中间的全部操作
        stream.forEach(System.out::println);
    }

    private static List<PrizeNot> listx = new ArrayList<>();
    /**
     * 映射
     * map--接受lambda，将元素转换成其他形式或提取信息，接收一个函数作为参数，该函数会被应用到每个元素，并将其映射成一个新元素。
     * fiatmap -- 接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流
     *
     */
    @Test
    public void test3(){
        List<String> list = Arrays.asList("aaaa","ccc","bbbb");
        list = Arrays.asList("1,2,3,4","2,3,5,6","3,7,8,9","3,9,6,9");
//        list.stream().map()
        Stream<String> stringStream = list.stream().map(s -> s.toUpperCase());
//        List<String> collect = list.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());
        System.out.println("______________________________");
        list.stream().forEach(TestStream::filterIntlist);
        listx.stream().map(TestStream::maxPirzenot).forEach(System.out::println);
//        Map<Integer, List<jdk8.PrizeNot>> collect1 = prizeNotStream.collect(Collectors.groupingBy(jdk8.PrizeNot::getPostion));
        System.out.println("_____________fiatmap_________________");
//        Stream<Integer>  stream = list.stream().flatMap(jdk8.TestStream::filterInt);
//        stream.forEach(System.out::println);
    }

    private static PrizeNot maxPirzenot(PrizeNot prizeNot) {
        Optional<PirzeNotIn> collect = prizeNot.getUnprizenums().stream()
                .collect(Collectors.maxBy((x, y) -> Integer.compare(x.getTimes(), y.getTimes())));
        prizeNot.setMaxunprize(collect.get());
        return prizeNot;
    }

    public static void filterIntlist(String str){
        List<String> list1 = Arrays.asList("1","2","3","4","5","6","7","8","9","10");
        for(int i=0;i<str.split(",").length;i++){
            if(i+1==2||i+1==3) {
                int index= i;
                PrizeNot prizeNot = new PrizeNot();
                List<String> list2 = new ArrayList<>();
                if(listx!=null
                        && listx.size()>0
                        && listx.stream().anyMatch(x->x.getPostion()==index+1)){
                    Optional<PrizeNot> first = listx.stream().
                            filter(x -> x.getPostion() == index + 1).
                            findFirst();
                    List<PirzeNotIn> collect = first.map(PrizeNot::getUnprizenums)
                            .get().stream()
                            .map(x -> {
                                if(!x.getNum().equals(str.split(",")[index])) {
                                    x.setNum(x.getNum());
                                }
                                return x;
                            })
                            .collect(Collectors.toList());
                    first.get().setUnprizenums(collect);
                }else {
                    list2 = list1.stream().filter(x -> !x.contains(str.split(",")[index])).collect(Collectors.toList());
                    List<PirzeNotIn> collect = list2.stream()
                            .map(x -> {
                                PirzeNotIn pirzeNotIn = new PirzeNotIn();
                                pirzeNotIn.setNum(x);
                                return pirzeNotIn;
                            }).collect(Collectors.toList());
                    prizeNot.postion = i+1;
                    prizeNot.unprizenums = collect;
                    listx.add(prizeNot);
                }
            }
        }
    }
    public static Stream<Integer> filterInt(String str){
        List<Integer> list = new ArrayList<>();
        for(String ch:str.split(",")){
            list.add(Integer.valueOf(ch));
        }
        return list.stream();
    }
    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for(Character ch:str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }

    /**
     * 排序
     * sorted()--自然排序(Comparable)
     * sorted(Comparator com)--定制排序
     */
    @Test
    public void test4(){
        List<String> list = Arrays.asList("zzzzz","9999","aaaa","ccc","bbbb");
        list.stream().sorted().forEach(System.out::println);
        System.out.println("______________________________");
        list.stream()
                .sorted((x,y)-> Integer.valueOf(x.length()).compareTo(Integer.valueOf(y.length())))
                .forEach(System.out::println);
    }
    /**
     * 查找与匹配
     * allMatch--检查是否匹配所有元素
     * anyMatch--检查是否至少匹配一个元素
     * noneMatch--检查是否没有匹配所有元素
     * findFirst--返回第一个元素
     * findAny--返回当前流中的任意元素
     * count--返回流中元素的总个数
     * max--返回流中的最大元素
     * min---返回流中的最小元素
     */
    @Test
    public void test5(){
        List<String> list = Arrays.asList("zzzzz","9999","aaaa","ccc","bbbb");
        boolean b1 = list.stream()
                            .allMatch(e->e.length()>2);
        System.out.println(b1);
        System.out.println("______________________________");
        boolean b2 = list.stream()
                .anyMatch(e->e.length()>5);
        System.out.println(b2);
        System.out.println("______________________________");
        boolean b3 = list.stream()
                .noneMatch(e->e.length()>5);
        System.out.println(b3);
        System.out.println("______________________________");
        Optional<String> optional = list.stream()
            .sorted((x,y)->-Integer.valueOf(y.length()).compareTo(Integer.valueOf(x.length())))
            .findFirst();
        System.out.println(optional.get());
        System.out.println("______________________________");
        Optional<String> optional1 = list.parallelStream()
                .filter(x->x.length()<4)
                .findAny();
        System.out.println(optional1.get());
        System.out.println("______________________________");
        Long count = list.stream().count();
        System.out.println(count);
        System.out.println("______________________________");
        Optional<String> optional3 = list.stream()
                .max((x,y)->Integer.valueOf(y.length()).compareTo(Integer.valueOf(x.length())));
        System.out.println(optional3.get());
        System.out.println("______________________________");
        Optional<String> optional4 = list.stream()
                .min((x,y)->Integer.valueOf(y.length()).compareTo(Integer.valueOf(x.length())));
        System.out.println(optional4.get());
        System.out.println("______________________________");
        Optional<Integer> integerOptional= list.stream()
                .map(String::length)
                .min(Integer::compare);
        System.out.println(integerOptional.get());
    }
    //终止操作
    /**
     * 归约
     * reduce(T identity,BinaryOperator)/reduce(BinaryOperator)--可以将流中元素反复结合起来，得到一个值
     */
    @Test
    public void test6(){
        List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream()
                .reduce(0,(x,y)->x+y);
        System.out.println(sum);
        System.out.println("______________________________");

        Optional<Double> optional= employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(optional.get());
    }

    /**
     * 收集
     * collect--将流转换为其他形式，接收一个Collector接口的实现，用于给Stream中元素做汇总的方法
     *
     */
    @Test
    public void test7(){
        List<String> list=employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        System.out.println("______________________________");
        HashSet<String> hashSet = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));

        //总数
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);
        System.out.println("______________________________");
        //平均值
        Double aDouble = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(aDouble);
        System.out.println("______________________________");
        //总和
        Double sumDouble = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sumDouble);
        System.out.println("______________________________");
        //最大值
        Optional<Employee> optional= employees.stream()
                .collect(Collectors.maxBy((x,y)->Double.compare(x.getSalary(),y.getSalary())));
        System.out.println(optional.get());
        System.out.println("______________________________");
        //最小工资
       Optional<Double> doubleOptional= employees.stream()
                .map(Employee::getSalary)
//                .collect(Collectors.minBy((x,y)->Double.compare(x,y)));
               .collect(Collectors.minBy(Double::compare));
        System.out.println(doubleOptional.get());
        System.out.println("______________________________");

        //分组
        Map<String,List<Employee>> map= employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
        System.out.println("______________________________");
        //多级分组
        Map<String,Map<String,List<Employee>>> mapMap= employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy(x->{
                    if (((Employee) x).getAge()>=20 && ((Employee) x).getAge()<=35){
                        return "青年";
                    }else if(((Employee) x).getAge()<20){
                        return "少年";
                    }else{
                        return "中年";
                    }
                })));
        System.out.println(mapMap);
        System.out.println("______________________________");

        //分区
        Map<Boolean,List<Employee>> map1 = employees.stream()
                .collect(Collectors.partitioningBy(x->x.getSalary()>10000));
        System.out.println(map1);
        System.out.println("______________________________");
        //分区
        DoubleSummaryStatistics collect = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(collect.getAverage());
        System.out.println(collect.getCount());
        System.out.println(collect.getMax());
        System.out.println(collect.getMin());
        System.out.println(collect.getSum());
        System.out.println("______________________________");
        //连接
        String collect1 = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining());
        System.out.println(collect1);
        String collect2 = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(","));
        System.out.println(collect2);
        String collect3 = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",","----","----"));
        System.out.println(collect3);
        System.out.println("______________________________");
    }
    //练习
    //1、给定【1，2，3,4,5】数组，得到平方和数组
    @Test
    public void test8(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        List<Integer> list1=list.stream()
                .map(x->x*x)
                .collect(Collectors.toList());
        list1.forEach(System.out::println);
    }
    //2、利用map和reduce计算流中多少个Employee
    @Test
    public void test9(){
        Optional<Integer> reduce = employees.stream()
                .map(e -> 1)
                .reduce(Integer::sum);
        System.out.println(reduce.get());
    }
}
